package com.inno.sms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.inno.sms.dict.Constant;
import com.inno.sms.dto.SmsInfoDTO;
import com.inno.sms.entity.PlannerSmsInfo;
import com.inno.sms.enums.IsUseEnum;
import com.inno.sms.enums.SmsTypeEnum;
import com.inno.sms.error.SmsException;
import com.inno.sms.mapper.PlannerSmsInfoDao;
import com.inno.sms.redis.RedisUtil;
import com.inno.sms.service.PlannerSmsInfoService;
import com.inno.sms.utils.SmsUtil;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

import java.util.Date;
import java.util.Objects;


/**
 * (PlannerSmsInfo)表服务实现类
 *
 * @author makejava
 * @since 2024-11-22 22:44:51
 */
@Service("plannerSmsInfoService")
public class PlannerSmsInfoServiceImpl implements PlannerSmsInfoService {
    @Resource
    private PlannerSmsInfoDao plannerSmsInfoDao;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private DataSourceTransactionManager transactionManager;
    @Resource
    private TransactionDefinition transactionDefinition;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public PlannerSmsInfo queryById(Long id) {
        return this.plannerSmsInfoDao.queryById(id);
    }


    /**
     * 新增数据
     *
     * @param plannerSmsInfo 实例对象
     * @return 实例对象
     */
    @Override
    public PlannerSmsInfo insert(PlannerSmsInfo plannerSmsInfo) {
        this.plannerSmsInfoDao.insert(plannerSmsInfo);
        return plannerSmsInfo;
    }

    /**
     * 修改数据
     *
     * @param plannerSmsInfo 实例对象
     * @return 实例对象
     */
    @Override
    public PlannerSmsInfo update(PlannerSmsInfo plannerSmsInfo) {
        this.plannerSmsInfoDao.update(plannerSmsInfo);
        return this.queryById(plannerSmsInfo.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long id) {
        return this.plannerSmsInfoDao.deleteById(id) > 0;
    }

    @Override
    public void sendSms(SmsInfoDTO smsInfoDTO) {
        PlannerSmsInfo plannerSmsInfo = this.convertDTOToEntity(smsInfoDTO);
        String mobile = plannerSmsInfo.getMobile();
        String smsContent = plannerSmsInfo.getSmsContent();
        String smsType = plannerSmsInfo.getSmsType();

        // TODO 后续短信业务发送类型变多  优化为策略模式做
        if (SmsTypeEnum.LOGIN_REGISTER.getCode().equals(smsType)) {
            if (!this.checkAlreadyExist(mobile)) {
                throw SmsException.of("发送短信过于频繁,请五分钟后重试!");
            }
            // 落库
            TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
            try {
                this.insert(plannerSmsInfo);
                redisUtil.set(Constant.SMS_CODE_CACHE_KEY + mobile, smsContent, Constant.SMS_CODE_EXPIRE_TIME);
                SmsUtil.sendCode(mobile, smsContent);
                transactionManager.commit(status);
            } catch (Exception e) {
                // 异常情况 回滚数据库及redis
                transactionManager.rollback(status);
                redisUtil.del(Constant.SMS_CODE_CACHE_KEY + mobile);
                throw SmsException.of("短信发送失败");
            }

        }

    }

    @Override
    public Boolean validate(SmsInfoDTO smsInfoDTO) {
        String mobile = smsInfoDTO.getMobile();

        Object cache = redisUtil.get(Constant.SMS_CODE_CACHE_KEY + mobile);
        if (Objects.isNull(cache)){
            return false;
        }
        String code = cache.toString();
        if (!StringUtils.equals(code, smsInfoDTO.getSmsContent())) {
            return false;
        }
        try {
            PlannerSmsInfo entity = new PlannerSmsInfo();
            entity.setUserId(smsInfoDTO.getUserId());
            entity.setMobile(mobile);
            entity.setSmsContent(code);
            entity.setUpdateTime(new Date());
            entity.setIsUse(IsUseEnum.YES.getCode().toString());
            this.plannerSmsInfoDao.updateByIsUseAndMobile(entity);
            redisUtil.del(Constant.SMS_CODE_CACHE_KEY + mobile);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 校验该手机号五分钟内是否发送过
     *
     * @return
     */
    public boolean checkAlreadyExist(String mobile) {
        Object obj = redisUtil.get(Constant.SMS_CODE_CACHE_KEY + mobile);
        return obj == null;
    }

    private PlannerSmsInfo convertDTOToEntity(SmsInfoDTO smsInfoDTO) {
        PlannerSmsInfo plannerSmsInfo = new PlannerSmsInfo();
        BeanUtil.copyProperties(smsInfoDTO, plannerSmsInfo);
        plannerSmsInfo.setId(IdUtil.getSnowflakeNextId());
        plannerSmsInfo.setCreateTime(new Date());
        plannerSmsInfo.setUpdateTime(new Date());
        return plannerSmsInfo;
    }

}
